package net.aiion.weave.impl.bytecode.events;

import net.aiion.weave.asm.Opcodes;
import net.aiion.weave.asm.Type;
import net.aiion.weave.spi.bytecode.BytecodeVisitor;
import net.aiion.weave.spi.bytecode.events.ClassStartBytecodeEvent;

public class ClassStartBytecodeEventImpl extends BytecodeEventImpl implements ClassStartBytecodeEvent
{
    private int version;
    private int modifiers;
    private String name;
    private String signature;
    private String superName;
    private String[] interfaceNames;

    public ClassStartBytecodeEventImpl(final int aVersion, final int aModifiers, final String aName,
        final String aSignature, final String aSuperName, final String[] aInterfaceNames)
    {
        version = aVersion;
        modifiers = aModifiers;
        name = aName;
        signature = aSignature;
        superName = aSuperName;
        interfaceNames = aInterfaceNames;
    }

    @Override
    public int getType() {
        return CLASS_START;
    }

    @Override
    public void setVersion(final int aVersion) {
        version = aVersion;
    }

    @Override
    public int getVersion() {
        return version;
    }

    @Override
    public void setModifiers(final int aModifiers) {
        modifiers = aModifiers;
    }

    @Override
    public int getModifiers() {
        return modifiers;
    }

    @Override
    public boolean isInterface() {
        return (modifiers & Opcodes.ACC_INTERFACE) == Opcodes.ACC_INTERFACE;
    }

    @Override
    public boolean isAbstract() {
        return (modifiers & Opcodes.ACC_ABSTRACT) == Opcodes.ACC_ABSTRACT;
    }

    @Override
    public void setName(final String aName) {
        name = aName;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setSignature(final String aSignature) {
        signature = aSignature;
    }

    @Override
    public String getSignature() {
        return signature;
    }

    @Override
    public void setSuperName(final String aSuperName) {
        superName = aSuperName;
    }

    @Override
    public String getSuperName() {
        return superName;
    }

    @Override
    public void setInterfaces(final String[] aInterfaceNames) {
        interfaceNames = aInterfaceNames;
    }

    @Override
    public void addInterface(final String aInterfaceName) {
        if (containsInterface(aInterfaceName)) {
            return;
        }

        if (interfaceNames == null) {
            interfaceNames = new String[] {
                aInterfaceName
            };
            return;
        }

        final String[] newInterfaceNames = new String[interfaceNames.length + 1];
        System.arraycopy(interfaceNames, 0, newInterfaceNames, 0, interfaceNames.length);
        newInterfaceNames[interfaceNames.length] = aInterfaceName;
        interfaceNames = newInterfaceNames;
    }

    @Override
    public void addInterface(final Class<?> aInterface) {
        addInterface(Type.getInternalName(aInterface));
    }

    @Override
    public void removeInterface(final String aInterfaceName) {
        if (!containsInterface(aInterfaceName)) {
            return;
        }

        final String[] newInterfaceNames = new String[interfaceNames.length - 1];
        int currentIndex = 0;
        for (String interfaceName : interfaceNames) {
            if (!interfaceName.equals(aInterfaceName)) {
                newInterfaceNames[currentIndex++] = interfaceName;
            }
        }
        interfaceNames = newInterfaceNames;
    }

    @Override
    public boolean containsInterface(final String aInterfaceName) {
        if (interfaceNames == null) {
            return false;
        }

        for (String interfaceName : interfaceNames) {
            if (interfaceName.equals(aInterfaceName)) {
                return true;
            }
        }

        return false;
    }

    @Override
    public boolean containsInterface(final Class<?> aInterface) {
        return containsInterface(Type.getInternalName(aInterface));
    }

    @Override
    public String[] getInterfaceNames() {
        return interfaceNames;
    }

    @Override
    public BytecodeVisitor acceptBytecodeVisitor(final BytecodeVisitor aBytecodeVisitor) {
        aBytecodeVisitor.asBytecodeClassVisitor().visitClassStart(this);
        return aBytecodeVisitor;
    }
}
